﻿//-----------------------------------------------------------------------
// <copyright file="FlagSet.cs" company="Bugger Sisters Inc.">
//     Copyright (c) Bugger Sisters Inc. All rights reserved.
// </copyright>
// <author>Sergey Tyshkovets</author>
//-----------------------------------------------------------------------

namespace MagicTheGathering.Core
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;

    public class FlagSet<T, TEnum> : IEnumerable<FlagSet<T, TEnum>> where TEnum : struct
    {
        #region [Protected fields and properties]

        protected readonly HashSet<TEnum> items = new HashSet<TEnum>();

        protected IEnumerable<FlagSet<T, TEnum>> ProjectedItems
        {
            get
            {
                return items.Select(i => new FlagSet<T, TEnum>(i));
            }
        }

        #endregion

        #region [Base constructors]

        protected FlagSet(TEnum flag)
        {
            items.Add(flag);
        }

        public FlagSet()
        {
        }

        #endregion

        #region [Has / Add / Remove]

        public Boolean Has(FlagSet<T, TEnum> item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            return item.items.IsSubsetOf(items);
        }

        public void Add(FlagSet<T, TEnum> item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            foreach (var singleItem in item.items)
            {
                items.Add(singleItem);
            }
        }

        public void Add(params FlagSet<T, TEnum>[] itemsArray)
        {
            foreach (var flagSet in itemsArray)
            {
                Add(flagSet);
            }
        }

        public void Remove(FlagSet<T, TEnum> item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            foreach (var singleItem in item.items)
            {
                items.Remove(singleItem);
            }
        }

        public void Remove(params FlagSet<T, TEnum>[] itemsArray)
        {
            foreach (var flagSet in itemsArray)
            {
                Remove(flagSet);
            }
        }

        public Int32 Count
        {
            get
            {
                return items.Count;
            }
        }

        #endregion

        #region Implementation of IEnumerable

        public IEnumerator<FlagSet<T, TEnum>> GetEnumerator()
        {
            return ProjectedItems.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        #region [Equality]

        public override Int32 GetHashCode()
        {
            return items.Sum(enumItem => Convert.ToInt32(enumItem));
        }

        public static Boolean operator ==(FlagSet<T, TEnum> c1, FlagSet<T, TEnum> c2)
        {
            if (ReferenceEquals(c1, c2))
            {
                return true;
            }

            if (ReferenceEquals(c1, null) || ReferenceEquals(c2, null))
            {
                return false;
            }

            return (c1.items.IsSubsetOf(c2.items) && c1.items.IsSupersetOf(c2.items));
        }

        public static bool operator !=(FlagSet<T, TEnum> c1, FlagSet<T, TEnum> c2)
        {
            return !(c1 == c2);
        }

        public override Boolean Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (this.GetType() != obj.GetType())
            {
                return false;
            }

            var enumItem = (FlagSet<T, TEnum>)obj;

            return (this == enumItem);
        }

        #endregion
    }
}
